/**
  ******************************************************************************
  * @file    mx_wifi_io.c
  * @author  MCD Application Team
  * @brief   This file implements the IO operations to deal with the mx_wifi
  *          module. It mainly Inits and Deinits the UART interface. Send and
  *          receive data over it.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */

/*****************************************************************************
  * this file can be copy and renamed as net_conf.c or use directly from its
  * orginal location  STM32_Network_lib/templates. There is no need to chnage it.
  *
  * It performs the connection between the mxchip BSP driver and the UART
  *
  *  Expectaction is that UART pins labels are defined in main.h (when using
  *  CUbeMX) or in net_conf.h.
  *
  *  function  HAL_UART_MspInit(UART_HandleTypeDef* huart) in file
  *  stm32xxxx_hal_msp.c must performed the init of the selected UART interface
  *  This function can be manualy written or generated by cubeMX
  *
  *  UART parameter init is done in this file in a redundant way from
  *  the HAL_UART_MspInit function.CubeMX user does not have to know the exact
  *  configuratino of the UART , but only the pin out connections.
  *
  *  When interrupt are used (NET_USE_RTOS) , the function MXchip_UART_RxCpltCallback
  *  must be called from HAL_UART_RxCpltCallback located in main.c. A dedicated
  *  IRQHandler must be added to the file stm32xxx_it.C to call the HAL_UART_IRQHandler
  *
  * the function MX_WIFI_RESET_IO_Initconfigure the reset pins. It should be generated by
  * CubeMX et being located in main.c
  */
/* Includes ------------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
#include <main.h>
#include <string.h>
#include "net_conf.h"
#include "mx_wifi.h"
#if (MX_WIFI_USE_SPI == 0)

/* Private define ------------------------------------------------------------*/
#if (osCMSIS < 0x20000U )
#define OSSEMAPHOREWAIT osSemaphoreWait
#else
#define OSSEMAPHOREWAIT osSemaphoreAcquire
#endif /* osCMSIS */


#define MX_WIFI_RESET_MODULE()      do{\
                                        HAL_GPIO_WritePin(MX_WIFI_RESET_IO_PORT, MX_WIFI_RESET_IO_PIN, GPIO_PIN_RESET);\
                                        HAL_Delay(10);\
                                        HAL_GPIO_WritePin(MX_WIFI_RESET_IO_PORT, MX_WIFI_RESET_IO_PIN, GPIO_PIN_SET);\
                                        HAL_Delay(10);\
                                      }while(0);

#if MX_WIFI_USE_UART_INTERRUPT
#define RING_BUFFER_SIZE          (MX_WIFI_DATA_SIZE + 500)
typedef struct
{
  uint8_t  data[RING_BUFFER_SIZE];
  __IO    uint16_t tail;
  __IO    uint16_t head;
} RingBuffer_t;
#endif /* MX_WIFI_USE_UART_INTERRUPT */

MX_WIFIObject_t *wifi_obj_get(void);



UART_HandleTypeDef              mx_uart;
static MX_WIFIObject_t    MxWifiObj;
#if MX_WIFI_USE_UART_INTERRUPT
__IO        RingBuffer_t            WiFiRxBuffer;
#endif /* MX_WIFI_USE_UART_INTERRUPT */
#ifdef NET_USE_RTOS
osSemaphoreId wifi_uart_rx_sem;
osSemaphoreDef(wifi_uart_rx_sem);
#endif /* NET_USE_RTOS */


/* Private variables ---------------------------------------------------------*/

MX_WIFIObject_t *wifi_obj_get(void)
{
  return &MxWifiObj;
}



static   void MX_WIFI_IO_DELAY(uint32_t ms)
{
#if MX_WIFI_USE_CMSIS_OS
  osDelay(ms);
#else
  HAL_Delay(ms);
#endif /* MX_WIFI_USE_CMSIS_OS */
}


/**
  * @brief GPIO Initialization Function for WIFI reset IO
  * @param None
  * @retval None
  */
static void MX_WIFI_RESET_IO_Init(void)
{
  GPIO_InitTypeDef GPIO_Init;

  MX_WIFI_RESET_IO_CLK_ENABLE();

  /* configure Reset pin for Mxchip */
  HAL_GPIO_WritePin(MX_WIFI_RESET_IO_PORT, MX_WIFI_RESET_IO_PIN, GPIO_PIN_SET);
  GPIO_Init.Pin       = MX_WIFI_RESET_IO_PIN;
  GPIO_Init.Mode      = GPIO_MODE_OUTPUT_PP;
  GPIO_Init.Pull      = GPIO_NOPULL;
  GPIO_Init.Speed     = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(MX_WIFI_RESET_IO_PORT, &GPIO_Init);
}

#ifdef NET_MXCHIP_LOCAL_MSP
/**
  * @brief UART MSP Initialization
  * This function configures the hardware resources used in this example
  * @param huart: UART handle pointer
  * @retval None
  */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
  GPIO_InitTypeDef  GPIO_InitStruct = {0};

  if (huart->Instance == USARTmxc)
  {
    /*##-1- Enable peripherals and GPIO Clocks #################################*/
    /* Enable GPIO TX/RX clock */
    USARTmxc_TX_GPIO_CLK_ENABLE();
    USARTmxc_RX_GPIO_CLK_ENABLE();

    /* Enable USARTx clock */
    USARTmxc_CLK_ENABLE();


    /*##-2- Configure peripheral GPIO ##########################################*/
    /* UART TX GPIO pin configuration  */
    GPIO_InitStruct.Pin       = USARTmxc_TX_PIN;
    GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull      = GPIO_PULLUP;
    GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = USARTmxc_TX_AF;

    HAL_GPIO_Init(USARTmxc_TX_GPIO_PORT, &GPIO_InitStruct);

    /* UART RX GPIO pin configuration  */
    GPIO_InitStruct.Pin = USARTmxc_RX_PIN;
    GPIO_InitStruct.Alternate = USARTmxc_RX_AF;

    HAL_GPIO_Init(USARTmxc_RX_GPIO_PORT, &GPIO_InitStruct);
  }
}

/**
  * @brief UART MSP De-Initialization
  * This function freeze the hardware resources used in this example
  * @param huart: UART handle pointer
  * @retval None
  */
void HAL_UART_MspDeInit(UART_HandleTypeDef *huart)
{
  if (huart->Instance == USARTmxc)
  {
    USARTmxc_FORCE_RESET();
    USARTmxc_RELEASE_RESET();

    USARTmxc_CLK_DISABLE();

    /*##-2- Disable peripherals and GPIO Clocks ################################*/
    /* Configure UART Tx as alternate function  */
    HAL_GPIO_DeInit(USARTmxc_TX_GPIO_PORT, USARTmxc_TX_PIN);
    /* Configure UART Rx as alternate function  */
    HAL_GPIO_DeInit(USARTmxc_RX_GPIO_PORT, USARTmxc_RX_PIN);
  }
}

#endif /* NET_MXCHIP_LOCAL_MSP */

/**
  * @brief  Initialize the UART
  * @param  None
  * @retval None
  */
static int8_t MX_WIFI_UART_Init(uint16_t mode)
{
  int8_t  rc = 0;

  MX_WIFI_RESET_IO_Init();

  if (MX_WIFI_RESET == mode)
  {
    MX_WIFI_RESET_MODULE();
  }
  else
  {
    /* Configurate the UART to correct speed */
    mx_uart.Instance = USARTmxc;
    mx_uart.Init.BaudRate = MX_WIFI_UART_BAUDRATE;
    mx_uart.Init.WordLength = UART_WORDLENGTH_8B;
    mx_uart.Init.StopBits = UART_STOPBITS_1;
    mx_uart.Init.Parity = UART_PARITY_NONE;
    mx_uart.Init.Mode = UART_MODE_TX_RX;
    mx_uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    mx_uart.Init.OverSampling = UART_OVERSAMPLING_16;
    mx_uart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
#ifdef UART_PRESCALER_DIV1
    mx_uart.Init.ClockPrescaler = UART_PRESCALER_DIV1;
#endif /* UART_PRESCALER_DIV1 */
    mx_uart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
    if (HAL_UART_Init(&mx_uart) != HAL_OK)
    {
      while (1);
    }
#if  MX_WIFI_USE_UART_INTERRUPT
    WiFiRxBuffer.head = 0;
    WiFiRxBuffer.tail = 0;
#endif /* MX_WIFI_USE_UART_INTERRUPT */

#ifdef NET_USE_RTOS
#if (osCMSIS < 0x20000U )
    wifi_uart_rx_sem = osSemaphoreCreate(osSemaphore(wifi_uart_rx_sem), 1);
#else
    wifi_uart_rx_sem = osSemaphoreNew(1, 1, NULL);
#endif /* osCMSIS */
    OSSEMAPHOREWAIT(wifi_uart_rx_sem, 1);
    HAL_NVIC_SetPriority(UARTmxc_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY, 0);
#else
    HAL_NVIC_SetPriority(UARTmxc_IRQn, 16, 0);
#endif /* NET_USE_RTOS */

    HAL_NVIC_EnableIRQ(UARTmxc_IRQn);
#if MX_WIFI_USE_UART_INTERRUPT
    HAL_UART_Receive_IT(&mx_uart, (uint8_t *)&WiFiRxBuffer.data[WiFiRxBuffer.tail], 1);
#endif /* MX_WIFI_USE_UART_INTERRUPT */
  }

  return rc;
}

/**
  * @brief  Deinitialize the UART
  * @param  None
  * @retval None
  */
static int8_t MX_WIFI_UART_DeInit(void)
{
  int8_t  rc = 0;

  if (HAL_UART_DeInit(&mx_uart) != HAL_OK)
  {
    while (1);
  }
#ifdef NET_USE_RTOS
  osSemaphoreDelete(wifi_uart_rx_sem);
#endif /* NET_USE_RTOS */

  return rc;
}


#if  MX_WIFI_USE_UART_INTERRUPT




/**
  * @brief  Rx Callback when new data is received on the UART.
  * @param  UartHandle: Uart handle receiving the data.
  * @retval None.
  */
void MXchip_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle);
void MXchip_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
  uint32_t     tail;
  /* WIFI UART */
  /* If ring buffer end is reached reset tail pointer to start of buffer */
  if (++WiFiRxBuffer.tail >= RING_BUFFER_SIZE)
  {
    WiFiRxBuffer.tail = 0;
  }

  /* ringbuffer full, overlap head */
  tail = WiFiRxBuffer.tail;
  if (tail == WiFiRxBuffer.head)
  {
    WiFiRxBuffer.head++;
  }
  // fired next reception
  HAL_UART_Receive_IT(UartHandle, (uint8_t *)&WiFiRxBuffer.data[WiFiRxBuffer.tail], 1);

#ifdef NET_USE_RTOS
  osSemaphoreRelease(wifi_uart_rx_sem);
#endif /* NET_USE_RTOS */
}




#endif /* MX_WIFI_USE_UART_INTERRUPT */

/**
  * @brief  Send wifi Data thru UART
  * @param  pdata : pointer to data
  * @param  len : Data length
  * @param  timeout : send timeout in mS
  * @retval Length of sent data
  */
static int16_t MX_WIFI_UART_SendData(uint8_t *pdata,  uint16_t len, uint32_t timeout)
{
  int16_t rc  = 0;

  if (HAL_UART_Transmit(&mx_uart, pdata, len, timeout) != HAL_OK)
  {
    return MX_WIFI_STATUS_IO_ERROR;
  }
  rc = len;
  /*DEBUG_LOG("MX_WIFI_TX: %d bytes, [%.*s]\r\n", len, len, pdata);*/

  return rc;
}

static int16_t MX_WIFI_UART_ReceiveData(uint8_t *pdata, uint16_t request_len, uint32_t timeout)
{
  int16_t len = 0;

#if    MX_WIFI_USE_UART_INTERRUPT==0
  len = request_len;
  if (HAL_UART_Receive(&mx_uart, pdata, len, timeout) != HAL_OK)
  {
    return MX_WIFI_STATUS_IO_ERROR;
  }
  /*DEBUG_LOG("MX_WIFI_RX: %d bytes, [%.*s]\r\n", len, len, pdata);*/
#else
  int32_t     tail;
#ifdef NET_USE_RTOS
  OSSEMAPHOREWAIT(wifi_uart_rx_sem, 1);
#endif /* NET_USE_RTOS */
  tail = WiFiRxBuffer.tail;
  len = ((RING_BUFFER_SIZE + tail - WiFiRxBuffer.head) % RING_BUFFER_SIZE);
  if (len == 0)
  {
    return 0;
  }

  if (len  > request_len)
  {
    len = request_len;
  }

  /*copy from buffer */
  for (uint32_t i = 0; i < len; i++)
  {
    *pdata++ = WiFiRxBuffer.data[WiFiRxBuffer.head++];
    if (WiFiRxBuffer.head >= RING_BUFFER_SIZE)
    {
      /* wrap */
      WiFiRxBuffer.head = 0;
    }
  }

#endif /* MX_WIFI_USE_UART_INTERRUPT */
  return len;
}


/**
  * @brief  probe function to register wifi to connectivity framwotk
  * @param  None
  * @retval None
  */
int32_t wifi_probe(void **ll_drv_context)
{
  if (MX_WIFI_RegisterBusIO(&MxWifiObj,
                            MX_WIFI_UART_Init,
                            MX_WIFI_UART_DeInit,
                            MX_WIFI_IO_DELAY,
                            MX_WIFI_UART_SendData,
                            MX_WIFI_UART_ReceiveData) == 0)
  {
    *ll_drv_context = &MxWifiObj;
    return 0;
  }

  return -1;
}


#endif /* MX_WIFI_USE_SPI */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
